#include "Col.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "Set.h"
#include "Class.h"

#include "IterIter.h"

#include "Error.h"
#include "RobustHashTable.h"

//---- Set ---------------------------------------------------------------------

NewMetaImpl(Set,Collection, (TP(ht)));

Set::Set(int initCapacity)
{
	Init(initCapacity);
}

Set::~Set()
{
	SafeDelete(ht);
}

void Set::InitNew()
{
	Collection::InitNew();
	Init(cContainerInitCap);
}

void Set::Empty(int newCapacity)
{
	if (HasIterators())
		ForEachIterDo(SetIter, SavePosition(ht->cInvalidIndex));
	ht->Empty(newCapacity);
	if (HasIterators())
		ForEachIterDo(SetIter, ResetPosition());
}

void Set::FreeAll()
{
	Object *op;

	if (HasIterators())
		ForEachIterDo(SetIter, SavePosition(ht->cInvalidIndex));
	int i= ht->GetInitialIndex();
	while (op= (Object*) ht->AtNextIndex(i)) {
		op->FreeAll();
		delete op;
	}
	ht->Empty(cContainerInitCap);
	if (HasIterators())
		ForEachIterDo(SetIter, ResetPosition())
}

int Set::Capacity()
{
	return ht->Capacity();
}

Object *Set::Add(Object *op)
{
	if (IsArgNull("Add", op))
		return 0;
	Object *result= (Object*) ht->Add(op);
	if (! result)
		Changed();
	return result;
}

Object *Set::Remove(Object *op)
{
	if (IsArgNull("Remove", op))
		return 0;
	Object *result= (Object*) ht->Remove(op, eEqValue);
	if (result)
		Changed();
	return result;
}

Object *Set::RemovePtr(Object *op)
{
	if (IsArgNull("RemovePtr", op))
		return 0;
	Object *result= (Object*) ht->Remove(op, eEqPointer);
	if (result)
		Changed();
	return result;
}

Iterator *Set::MakeIterator(bool, void *placement)
{
	return new(placement) SetIter(this);
}

Object *Set::Find(Object *op)
{
	if (IsArgNull("Find", op))
		return 0;
	return (Object*) ht->Find(op, eEqValue);
}

Object *Set::FindPtr(Object *op)
{
	if (IsArgNull("FindPtr", op))
		return 0;
	return (Object*) ht->Find(op, eEqPointer);
}

int Set::OccurrencesOf(Object *op)
{
	return Find(op) ? 1 : 0;
}

int Set::OccurrencesOfPtr(Object *op)
{
	return FindPtr(op) ? 1 : 0;
}

//---- statistics ----

double Set::AverageCollisions()
{
	return ht->AverageCollisions();
}

//---- initialization ----

Set::Set(Set*)
{
	ht= 0;
}

void Set::Init(int initCapacity)
{
	ht= new RobustHashTable(
		this, initCapacity, &ContainerTypes::pEqual, &ContainerTypes::pHash,
		&size);
}

//---- robust iterators ----

void Set::SaveItersPosition(int pix)
{
	ForEachIterDo(SetIter, SavePosition(pix));
}

void Set::ResetItersPosition()
{
	ForEachIterDo(SetIter, ResetPosition());
}

//---- SetIter ----------------------------------------------------------------

SetIter::SetIter(Set *aSet)
{
	set= aSet;
	ht= 0;
	pix= 0;
	saved= 0;
}

SetIter::~SetIter()
{
	Terminate();
}

Object *SetIter::operator()()
{
	Object *op;

	if (! Activated()) {
		if (Activate()) {
			ht= set->ht;
			pix= ht->GetInitialIndex();
		}
	}
	if (! Terminated()) {
		op= (Object*) ht->AtNextIndex(pix);
		if (! op)
			Terminate();
		return op;
	}
	return 0;
}

void SetIter::Reset()
{
	Iterator::Reset();
	pix= 0;
	saved= 0;
}

Container *SetIter::GetContainer()
{
	return set;
}

void SetIter::SavePosition(int forPix)
{
	if (IsActive()) {
		if (forPix == pix)
			saved= (Object*) ht->AtPrevIndex(pix);
		else
			saved= (Object*) ht->AtIndex(pix);
	} else
		Error("SetIter::SavePosition", "this is not active");
}

void SetIter::ResetPosition()
{
	if (IsActive()) {
		if (saved)
			pix= ht->IndexOf(saved, eEqPointer);
		else
			pix= ht->GetInitialIndex();
	} else
		Error("SetIter::SavePosition", "this is not active");
	saved= 0;
}

//---- IdSet -------------------------------------------------------------------

NewMetaImpl0(IdSet, Set);

IdSet::IdSet(int aCapacity) : Set(this)
{
	Init(aCapacity);
}

void IdSet::InitNew()
{
	Collection::InitNew();
	Init(cContainerInitCap);
}

void IdSet::Init(int aCapacity)
{
	ht= new RobustHashTable(
		this, aCapacity, &ContainerTypes::pIdentical,
		&ContainerTypes::pHashPtr, &size);
}

